﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// BW = imregionalmax(I) finds the regional maxima of I. 
    /// imregionalmax returns the binary image BW that identifies the locations of the regional maxima in I.
    /// BW is the same size as I. 
    /// In BW, pixels that are set to 1 identify regional maxima; 
    /// all other pixels are set to 0.
    /// Regional maxima are connected components of pixels with a constant intensity value, 
    /// and whose external boundary pixels all have a lower value.
    /// By default, imregionalmax uses 8-connected neighborhoods for 2-D images and 26-connected neighborhoods for 3-D images. 
    /// For higher dimensions, imregionalmax uses conndef(ndims(I),'maximal').
    /// BW = imregionalmax(I,conn) computes the regional maxima of I using the specified connectivity.
    /// conn can have any of the following scalar values:
    /// 4, 8, 6, 16, 26
    /// </summary>
    public class ImageRegionalMax : BaseForeBackgroundColorFilter
    {
        //TODO: check if this can be deleted (inheritance)
        protected Dictionary<NEIGHBOUR, List<Point>> m_aNeighbour = new Dictionary<NEIGHBOUR, List<Point>>() { 
            {NEIGHBOUR.EIGHT, Definitions.EnvironmentPointListClockwise},
            {NEIGHBOUR.FOUR, Definitions.EnvironmentPointList4Clockwise}
        };

        //TODO: check if this can be deleted (inheritance)
        protected NEIGHBOUR m_NEIGHBOUR = NEIGHBOUR.EIGHT;


        /// <summary>
        /// Initializes a new instance of the <see cref="ImageRegionalMax"/> class.
        /// </summary>
        public ImageRegionalMax()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ImageRegionalMax"/> class.
        /// </summary>
        /// <param name="_imageRegionalMax">The _image regional max.</param>
        internal ImageRegionalMax(ImageRegionalMax _imageRegionalMax)
        {
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nStart = -1;
            int nEnd = -1;

            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            int nValue = 0;
            int nLocalMaximum = int.MaxValue;

            UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
            UnsafeBitmap bitmapResult = (UnsafeBitmap)_bitmap.Clone();
            bitmapResult.Clear(Definitions.Black);
            int x = 0;
            int y = 0;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    nValue = bitmapCloned[x, y, true].R;
                    nLocalMaximum = int.MinValue;

                    //Find starting minimum value
                    while (nValue > nLocalMaximum)
                    {
                        nLocalMaximum = nValue;
                        if (x > nWidth - 2) break;
                        nValue = bitmapCloned[++x, y, true].R;
                    }

                    //found minimum

                    //Debug.Write(bitmapCloned[x-1,y, true].R + " ");
                    nStart = x - 1;

                    //find all values of same minimum
                    while (nValue == nLocalMaximum)
                    {
                        nValue = bitmapCloned[x++, y, true].R;
                        if (nValue == nLocalMaximum)
                        {
                            //Debug.Write(nValue + " ");
                            bitmapResult.SetPixelDirect(x - 1, y, Definitions.White);
                            if (x > nWidth - 2) break;
                        }
                    }
                    nEnd = x - 1;
                    //Debug.Write(string.Format(" [{0}, {1}]", nStartX, nEndX));

                    //Debug.WriteLine("");

                }
            }

            for (x = 0; x < nWidth; x++)
            {
                for (y = 0; y < nHeight; y++)
                {
                    nValue = bitmapCloned[x, y, true].R;
                    nLocalMaximum = int.MinValue;

                    //Find starting minimum value
                    while (nValue > nLocalMaximum)
                    {
                        nLocalMaximum = nValue;
                        if (y > nHeight - 2) break;
                        nValue = bitmapCloned[x, ++y, true].R;
                    }

                    //found minimum

                    //Debug.Write(bitmapCloned[x,y-1, true].R + " ");
                    nStart = y - 1;

                    //find all values of same minimum
                    while (nValue == nLocalMaximum)
                    {
                        nValue = bitmapCloned[x, y++, true].R;
                        if (nValue == nLocalMaximum)
                        {
                            //Debug.Write(nValue + " ");
                            bitmapResult.SetPixelDirect(x, y - 1, Definitions.White);
                            if (y > nHeight - 2) break;
                        }
                    }
                    nEnd = y - 1;
                    //Debug.Write(string.Format(" [{0}, {1}]", nStartX, nEndX));

                    //Debug.WriteLine("");

                }
            }

            _bitmap.Clear(Definitions.Black);
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    if (bitmapResult.GetPixel(x, y) == Definitions.White)
                    {
                        _bitmap.SetPixel(x, y, Definitions.White);
                    }
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ImageRegionalMax(this);
        }
    }
}
